dnl This file is a part of Aurelia.
dnl Copyright (C) 2010  Valentin David
dnl Copyright (C) 2010  University of Bergen
dnl
dnl This program is free software: you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation, either version 3 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.

AC_DEFUN([NOTCXX0X], [
  AC_MSG_ERROR([$1. Is $CXX a C++0x compiler?])
])

AC_DEFUN([NOTCXX03], [
  AC_MSG_ERROR([$1. Is $CXX standard compliant?])
])

AC_DEFUN([CHECK_CXX0X_HEADER], [
  AC_LANG_PUSH([C++])
  AC_CHECK_HEADER([$1],[],[
    NOTCXX0X([Header $1 set is missing])
  ])
  AC_LANG_POP
])

AC_DEFUN([CHECK_CXX03_HEADER], [
  AC_LANG_PUSH([C++])
  AC_CHECK_HEADER([$1],[],[
    NOTCXX03([Header $1 is missing])
  ])
  AC_LANG_POP
])

AC_DEFUN([CHECK_CXX0X_HEADERS], [
  AH_CHECK_HEADERS([$1])
  m4_map_args_w([$1],[CHECK_CXX0X_HEADER(],[)])
])

AC_DEFUN([CHECK_CXX03_HEADERS], [
  AH_CHECK_HEADERS([$1])
  m4_map_args_w([$1],[CHECK_CXX03_HEADER(],[)])
])

AC_DEFUN([CXX0X_FUNCTION],[
AC_MSG_CHECKING([whether std::function exists])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <functional>
struct Fun {
  int operator()(int) const {
    return 0;
  }
};
int test() {
  std::function<int(int)> f = Fun();
  return f(0);
}
]])],[AC_MSG_RESULT([yes])],[dnl
  AC_MSG_RESULT([no])
  NOTCXX0X([std::function is missing])
])
AC_LANG_POP
])

AC_DEFUN([CXX0X_LAMBDAS],[
AC_MSG_CHECKING([whether the compiler supports lambda expressions])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int test(int n) {
  return [] (int n) { return n; }(n);
}
]])],[AC_MSG_RESULT([yes])],[dnl
  AC_MSG_RESULT([no])
  NOTCXX0X([Lambda expression are not supported])
])
AC_LANG_POP
])

AC_DEFUN([CXX0X_TYPED_ENUMS],[
AC_MSG_CHECKING([whether enums can be typed])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
enum foo : unsigned { bar = 0 };
]])],[AC_MSG_RESULT([yes])],[dnl
  AC_MSG_RESULT([no])
  NOTCXX0X([Enumerations cannot be typed])
])
AC_LANG_POP
])

AC_DEFUN([CXX0X_AUTO],[
AC_MSG_CHECKING([whether keyword auto can be used as a type])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
int foo() {
  auto i = 0;
  return i;
}
]])],[AC_MSG_RESULT([yes])],[dnl
  AC_MSG_RESULT([no])
  NOTCXX0X([Keyword auto is not usable])
])
AC_LANG_POP
])

AC_DEFUN([CXX0X_DECLTYPE],[
AC_MSG_CHECKING([whether keyword decltype is supported])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
static int t;
decltype(t) foo() {
  return 0;
}
]])],[AC_MSG_RESULT([yes])],[dnl
  AC_MSG_RESULT([no])
  NOTCXX0X([Keyword decltype is not supported])
])
AC_LANG_POP
])

AC_DEFUN([CXX0X_FLAG],[
AC_MSG_CHECKING([whether the C++ compiler accepts -std=c++0x.])
AC_LANG_PUSH([C++])
oldCPPFLAGS="$CPPFLAGS"
CPPFLAGS="-std=c++0x $CPPFLAGS"
AC_COMPILE_IFELSE(
 [AC_LANG_SOURCE([[]])],
 [EXTRACPPFLAGS="-std=c++0x"
  AC_MSG_RESULT([yes])],
 [EXTRACPPFLAGS=""
  AC_MSG_RESULT([no])])
CPPFLAGS="$EXTRACPPFLAGS $oldCPPFLAGS"
AC_LANG_POP
])

AC_DEFUN([CXX_WALL],[
if ! test "$ac_test_CXXFLAGS" = set; then
  AC_LANG_PUSH([C++])
  oldCXXFLAGS="$CXXFLAGS"
  CXXFLAGS="$CXXFLAGS -W -Wall"
  AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],[],[CXXFLAGS="$oldCXXFLAGS"])
  AC_LANG_POP
fi
])

AC_DEFUN([CXX_WERROR],[
if ! test "$ac_test_CXXFLAGS" = set; then
  AC_LANG_PUSH([C++])
  oldCXXFLAGS="$CXXFLAGS"
  CXXFLAGS="$CXXFLAGS -Werror"
  AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],[],[CXXFLAGS="$oldCXXFLAGS"])
  AC_LANG_POP
fi
])

AC_DEFUN([CXX0X_THREAD_LOCAL],[
AC_MSG_CHECKING([whether the compiler supports thread_local])
AC_LANG_PUSH([C++])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int test() {
  thread_local int i = 10;
  return i;
}
]])],[AC_MSG_RESULT([yes])],[dnl
  AC_MSG_CHECKING([whether the compiler supports static __thread])
  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[int test() {
    static __thread int i = 10;
    return i;
  }
  ]])],[dnl
  AC_MSG_RESULT([yes])
  AC_DEFINE([thread_local],[static __thread],[Replacement for thread_local])
  ],[dnl
    AC_MSG_RESULT([no])
    NOTCXX0X([thread_local is not supported])
  ])
])
AC_LANG_POP
])
